package com.yungu.swift.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author Zerrion
 * @date 2017/10/24
 */
public class ReflectUtils {

    private ReflectUtils() {
    }

    /**
     * 反射取值
     */
    public static Object getFieldValue(Object instance, String fieldName) throws IllegalAccessException {
        Field field = getField(instance.getClass(), fieldName);
        if (field == null) {
            return null;
        }
        field.setAccessible(true);
        return field.get(instance);
    }


    /**
     * 反射赋值
     */
    public static void setFieldValue(Object instance, String fieldName, Object fieldValue) throws IllegalAccessException {
        Field field = getField(instance.getClass(), fieldName);
        if (field == null) {
            return;
        }
        field.setAccessible(true);
        field.set(instance, fieldValue);
    }

    /**
     * 执行方法
     */
    public static Object invokeMethod(Object instance, String methodName, Object... args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method method = getMethod(instance.getClass(), methodName, args);
        if (method == null) {
            return null;
        }
        method.setAccessible(true);
        return method.invoke(instance, args);
    }

    /**
     * 查找 Field 从子类往上找
     *
     * @param aClass
     * @param fieldName
     * @return
     * @throws NoSuchFieldException
     */
    private static Field getField(Class<?> aClass, String fieldName) {
        try {
            return aClass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            Class<?> superclass = aClass.getSuperclass();
            if (superclass.equals(Object.class)) {
                return null;
            }
            return getField(superclass, fieldName);
        }
    }

    /**
     * 查找 method，从子类往上找
     *
     * @param aClass
     * @param methodName
     * @param args
     * @return
     * @throws NoSuchMethodException
     */
    private static Method getMethod(Class<?> aClass, String methodName, Object... args) {
        Class<?>[] parameterTypes = new Class<?>[args.length];
        for (int i = 0; i < args.length; i++) {
            parameterTypes[i] = args[i].getClass();
        }
        try {
            return aClass.getDeclaredMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            Class<?> superclass = aClass.getSuperclass();
            if (superclass.equals(Object.class)) {
                return null;
            }
            return getMethod(superclass, methodName, args);
        }
    }

}
